package com.codefish.codefish_blog.redis;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.codefish.codefish_blog.entity.Article;
import com.codefish.codefish_blog.entity.User;
import com.codefish.codefish_blog.service.ArticleService;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.annotations.Delete;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;

/**
 * 文章相关Redis服务类
 *
 * @author codefish
 * @version 1.0
 * @date 2022/04/14 下午 07:14
 */
@Component
@Slf4j
public class RedisArticleService {
    @Resource
    RedisTemplate<String, Object> redisTemplate;
    @Autowired
    ArticleService articleService;
    /**
     * 标识自上一次同步至数据库后是否有新的文章访问产生,初始化为false
     */
    private static boolean updateFlag = false;

    /**
     * 根据文章id增加访问量并返回
     *
     * @param articleId 文章id
     * @return 文章id对于的访问量
     */
    public long increaseWatchCount(Long articleId) {
        //接收到新的文章访问增量，将访问标志位设为true
        updateFlag = true;
        //获取对redis的String进行操作的对象ops
        ValueOperations<String, Object> ops = redisTemplate.opsForValue();
        //从redis中查找文章id是否存在
        String key = Long.toString(articleId);
        Long value = this.getObj(ops.get(key));
        //key不存在，王redis中存入文章id和访问数，初始化为0
        if (value == null) {
            ops.set(key, 0L);
            value = 0L;
        }
        //key存在,文章浏览数加一
        ops.increment(key);
        //返回incr后的数据
        return value + 1;
    }

    /**
     * 将redis中的文章访问数据同步至MySQL
     * 通过定时任务周期调用
     */
    public void synToDB() {
        Long sTime = System.currentTimeMillis();
        //若访问标志位为false，则不需要同步到数据库
        if (!updateFlag) {
            log.info("自上次同步后并未产生新的文章访问，无需同步");
            return;
        }
        ValueOperations<String, Object> ops = redisTemplate.opsForValue();
        QueryWrapper<Article> wrapper = new QueryWrapper<>();
        wrapper.select("article_id");
        List<Article> list = articleService.list(wrapper);
        for (Article article : list) {
            String key = Long.toString(article.getArticleId());
            Long val = this.getObj(ops.get(key));
            if (val != null) {
                article.setWatched(val);
                articleService.updateById(article);
            }
        }
        //完成同步后将访问标志位置为false
        updateFlag = false;
        Long eTime = System.currentTimeMillis();
        log.info("redis同步文章访问量至数据库完成，耗时{}s", (eTime - sTime) / 1000.0);
    }

    /**
     * 解决redis中存入Long，取出时变为Integer的问题
     *
     * @param obj object
     * @return Long对象
     */
    private Long getObj(Object obj) {
        Long realObj = null;
        if (obj instanceof Integer) {
            realObj = (long) ((Integer) obj).intValue();
        } else if (obj instanceof Long) {
            realObj = (Long) obj;
        }
        return realObj;
    }

}
